﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using XDL.Framework;

namespace JumpNFight.Simulation
{
    /// <summary>
    /// Represents a tiled map.
    /// </summary>
    public class TileMap
    {
        /// <summary>
        /// Map width (in tiles unit)
        /// </summary>
        public int Width;

        /// <summary>
        /// Map height (in tiles height)
        /// </summary>
        public int Height;

        /// <summary>
        /// Tileset
        /// </summary>
        public Tileset Tileset;

        /// <summary>
        /// Background texture
        /// </summary>
        public Texture2D Background;

        /// <summary>
        /// Foreground texture
        /// </summary>
        public Texture2D Foreground;

        /// <summary>
        /// Map layers
        /// </summary>
        public List<TileMapLayer> Layers = new List<TileMapLayer>();

        bool m_isInitialized = false;

        public TileMap(ContentReader input)
        {
            Width = input.ReadInt32();
            Height = input.ReadInt32();
            bool isTilesetRef = input.ReadBoolean();
            if (isTilesetRef)
            {
                Tileset = input.ReadExternalReference<Tileset>();
            }
            else
            {
                Tileset = new Tileset(input);
            }
            int layerCount = input.ReadInt32();
            for(int i=0;i<layerCount;i++)
                Layers.Add(new TileMapLayer(input));
        }

        public Texture2D RenderLayer(Game game, string layerName)
        {
            GraphicsDevice graphicsDevice = game.GraphicsDevice;
            RenderTarget2D renderTarget = new RenderTarget2D(graphicsDevice, Width * 32, Height * 32, false, SurfaceFormat.Color, DepthFormat.None);
            graphicsDevice.SetRenderTarget(renderTarget);
            graphicsDevice.Clear(Color.Transparent);
            using (SpriteBatch spriteBatch = new SpriteBatch(graphicsDevice))
            {
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.PointClamp, DepthStencilState.Default, RasterizerState.CullNone);
                TileMapLayer layer = Layers.Find((l) => l.Name == layerName);
                if (layer != null)
                {
                    foreach (KeyValuePair<int, int> tile in layer.Tiles)
                    {
                        Vector2i targetTile = new Vector2i(tile.Key % layer.Width, tile.Key / layer.Width);
                        Vector2i sourceTile = new Vector2i(tile.Value % Tileset.Width, tile.Value / Tileset.Width);
                        spriteBatch.Draw(
                            Tileset.TilesetTexture,
                            new Rectangle(targetTile.X * 32, targetTile.Y * 32, 32, 32),
                            new Rectangle(sourceTile.X * 16, sourceTile.Y * 16, 16, 16),
                            Color.White);
                    }
                }
                spriteBatch.End();
            }
            graphicsDevice.SetRenderTarget(null);
            m_isInitialized = true;
            return renderTarget;
        }

        public List<Vector2i> GetTilesByType(string typeName)
        {
            List<Vector2i> tiles = new List<Vector2i>();
            TileMapLayer layer = Layers.Find((l) => l.Name == "Metadata");
            foreach (KeyValuePair<int, int> tile in layer.Tiles)
            {
                Vector2i targetTile = new Vector2i(tile.Key % layer.Width, tile.Key / layer.Width);
                if (Tileset.GetTileType(tile.Value - 1) == typeName)
                    tiles.Add(targetTile);
            }
            return tiles;
        }

        public void Initialize(Game game)
        {
            if (m_isInitialized)
                return;

            m_isInitialized = true;
            Background = RenderLayer(game, "Background");
            Foreground = RenderLayer(game, "Foreground");
        }
    }
}
